perm filename ALARM.MAC[AL,HE] blob
sn#744183 filedate 1984-02-23 generic text, type C, neo UTF8
COMMENT ā VALID 00007 PAGES
C REC PAGE DESCRIPTION
C00001 00001
C00002 00002 Low-level routines for AL-ARM communication using the ethernet via pups
C00005 00003 Local data
C00007 00004 function initEther(var abortf: boolean): integer
C00009 00005 procedure openConnection
C00012 00006 alMessage & readPup
C00022 00007 Aux routins: SETOPUP & SNDPUP
C00025 ENDMK
Cā;
;Low-level routines for AL-ARM communication using the ethernet via pups
.TITLE ALARM
.DSABL GBL
.MCALL QIOW$S,QIO$S,ALUN$S,SETF$S,CLEF$S,WTSE$S,RDAF$S
.MCALL MRKT$S,CMKT$S
.GLOBL IO.KIL
.GLOBL IO.WLB
.GLOBL IO.RLB
.GLOBL $B72
;$B72 = DISPOSE label in PASCAL runtime system
;MISCELLANEOUS CONSTANTS
ENOUT = 8. ;Ethernet output channel
ENIN = 9. ;Ethernet input channel
ENEV1 = 9. ;Input event flags for receiving pup packets
ENEV2 = 10.
ENEVF1 = 000400 ;Masks for both input event flags
ENEVF2 = 001000 ;Masks for both input event flags
MSGSIZ = 116 ;AL-ARM message size
PUP = 1000 ;Pup packet identifier
PUPOV = 22.
ALPSIZ = PUPOV + MSGSIZ - 2 ;Length of AL-ARM message
PUPSIZ = 560.
SRC = 0 ;Packet's source
DEST = 1 ;Packet's destination
TYPE = 2 ;Packet type: 1000 = pup, 1001 = IP
LENGTH = 4 ;Packet length
PUPTYP = 6 ;Pup type
PUPCTL = 7 ;Transport control
PUPID = 10 ;Pup identification (2 words)
PUPID2 = 12
DSTHST = 14 ;Destination host
DSTNET = 15 ;Destination network
DSTSOC = 16 ;Destination socket (2 words)
DSTSC2 = 20
SRCHST = 22 ;Source host
SRCNET = 23 ;Source network
SRCSOC = 24 ;Source socket (2 words)
SRCSC2 = 26 ;Source socket (2 words)
PDATA = 30 ;Start of data in pup
HELLOP = 200 ;Pup types for AL-ARM communication
ARMFRE = 201
ARMBSY = 202
THEREP = 203
ALLIVE = 204
ALARM = 205
ACK = 206
BYEBYE = 207
ARMSOC = 106 ;ARM server socket
;Local data
INPUP1: .BLKW PUPSIZ ;For receiving pups
INPUP2: .BLKW PUPSIZ
OUTPUP: .BLKW PUPOV+MSGSIZ ;For sending ALARM messages to AL
ACKPUP: .BLKW PUPOV ;Just pup overhead - no data bytes
THRPUP: .BLKW PUPOV ;Just pup overhead - no data bytes
BSYPUP: .BLKW PUPOV ;Just pup overhead - no data bytes
;Information defining current connection
HSTNUM: .BYTE 304,50 ;Host number/net of server - set by initEther
CONHST: .BYTE 0 ;Connection host - address of AL
CONNET: .BYTE 0 ;Connection net
CONSOC: .WORD 0 ;Connection socket
CONSC2: .WORD 0
CONDST: .WORD 0 ;Where we send pups to reach connection host
SEQIN: .WORD 0 ;Sequence number for input
SEQIN2: .WORD 0
SEQOUT: .WORD 0 ;Sequence number for output
SEQOU2: .WORD 0
TIMOUT: .WORD 0 ;Number of ticks that no messages passed
ACKTIM: .WORD 0 ;Number of ticks before retransmit
RETRY: .WORD 0 ;Number of times to retry transmission
IOACT: .WORD 0 ;Non-zero if any I/O activity this cycle
THEREC: .WORD 0 ;Waiting for AL alive reply
THERER: .WORD 0
OUTLST: .WORD 0 ;Head of list of messages to send to AL
IOSB: .BLKW 2
FLAGS: .BLKW 4
ABORTF: .WORD 0 ;Address of ARM's abort flag
MESREC: .WORD 0
INPMES: .WORD 0
;function initEther(var abortf: boolean): integer;
;ARM should call initEther once during initialization. The one parameter
;passed to initEther - abortf - will be set to TRUE (non-zero) whenever
;the AL-ARM connection is broken, i.e. AL sends a byebye packet or AL doesn't
;respond. It will be set FALSE (zero) when a connection is established by
;the openConnection routine. InitEther returns the ethernet number for the
;host machine. This is 304 (octal) for the 11/45, Ubehebe, and 323 for the
;11/60, Pisgah.
FUNC INITETHER,HNUM,INTEGER
PARAM ABTF,ADDRESS
SAVE <R0,R1,R2>
BEGIN
ALUN$S #ENOUT,#"EN,#0 ;Assign LUN for output
ALUN$S #ENIN,#"EN,#1 ;Assign LUN for input
MOV ABTF(SP),ABORTF ;Remember address of "abort" flag
CLR CONHST ;No connection open yet
;GET AND RETURN HOST ADDRESS
QIO$S #3000,#ENIN,,,#IOSB
MOV IOSB+2,HNUM(SP) ;HOST ADDRESS
MOVB IOSB+2,HSTNUM ;Save a copy for local use
ENDPR
;procedure openConnection
;Waits for AL to open a connection before returning.
;Sets the abort flag to FALSE.
PROC OPENCONNECTION
SAVE <R0,R1,R2>
BEGIN
QIO$S #IO.KIL,#ENIN ;Flush any pending pup reads
;Now wait for someone to say hello to us
;Accept any pup sent to ARM server socket from any host/socket
LOOP: QIOW$S #IO.RLB,#ENIN,#ENEV1,,,,<#INPUP1,#PUPSIZ,#ARMSOC,#0,#0,#0>
CMPB #HELLOP,INPUP1+PUPTYP ;Got one! Is it a HELLO packet?
BNE LOOP ; Nope - ignore it & wait for another
MOV INPUP1,CONDST ; Yes! - Get connection address
SWAB CONDST ;Net host who sent us pup (for gateways)
MOV INPUP1+SRCHST,CONHST ;Host/Net info
MOV INPUP1+SRCSOC,CONSOC ;Socket
MOV INPUP1+SRCSC2,CONSC2
MOV #ACKPUP,R1 ;Send RFC back to establish connection
JSR PC,SETOPUP ;First set up address info
MOVB #ARMFRE,ACKPUP+PUPTYP ;Tell AL that ARM is free
JSR PC,SNDPUP ;Send reply out
MOV #SEQIN,R1
MOV #11.,R0
10$: CLR (R1)+ ;Reset connection sequence numbers
SOB R0,10$ ; & various timers
CLRB @ABORTF ;Tell ARM connection established
;Enter two pup read requests & return to ARM
QIO$S #IO.RLB,#ENIN,#ENEV1,,,,<#INPUP1,#PUPSIZ,#ARMSOC,#0,#0,#0>
QIO$S #IO.RLB,#ENIN,#ENEV2,,,,<#INPUP2,#PUPSIZ,#ARMSOC,#0,#0,#0>
ENDPR
;alMessage & readPup
;function alMessage(inp,outp: messagep; ticks: integer): boolean;
;ARM passes two messages: one pointing to a free record for any message from AL
;and one (possibly NIL) pointing to a message to send to AL. If a message is
;received the function returns TRUE. The third parameter is used to tell the
;routine how long it has been since the last time it was scheduled (in 60ths of
;a second).
FUNC ALMESSAGE,MESP,BOOLEAN
PARAM INP,ADDRESS
PARAM OUTP,ADDRESS
PARAM TICKS,INTEGER
SAVE <R0,R1,R2,R3>
BEGIN
MOV INP(SP),INPMES ;Get AL-ARM message record
CLRB MESP(SP) ;Assume no message
CLR MESREC
CLR IOACT ;Assume nothing to do
RDAF$S #FLAGS ;See if any input to process
BIT #ENEVF1,FLAGS ;Pup 1 received?
BEQ 1$ ; No
MOV #INPUP1,R3 ; Yes - see what it says
JSR PC,READPU
MOVB MESREC,MESP(SP) ;Maybe a message now
QIO$S #IO.RLB,#ENIN,#ENEV1,,,,<#INPUP1,#PUPSIZ,#ARMSOC,#0,#0,#0>
1$: BIT #ENEVF2,FLAGS ;How about pup 2?
BEQ OUTQ ; No - deal with output
MOV #INPUP2,R3 ; Yes - see what it says
JSR PC,READPU
MOVB MESREC,MESP(SP) ;Maybe a message now
QIO$S #IO.RLB,#ENIN,#ENEV2,,,,<#INPUP2,#PUPSIZ,#ARMSOC,#0,#0,#0>
OUTQ: TST OUTP(SP) ;Any message for output?
BEQ 55$ ; No
MOV #OUTLST,R1 ; Yes - add it to output list
52$: TST (R1) ;Last entry in queue?
BEQ 53$ ; Yes
MOV (R1),R1 ; No - move down list
BR 52$
53$: MOV OUTP(SP),(R1) ;Add it to end of list
CLR @(R1) ; & zero its NEXT pointer
55$: TST ACKTIM ;Are we waiting for an ACK?
BEQ 60$ ; No
SUB TICKS(SP),ACKTIM ; Yes - update timer
BGT DONE ;Still waiting - skip ahead
MOV #1,R1 ;*** ACK time-out error
DEC RETRY ;Retransmit?
BLE ALDEAD ; No - time-out
MOV #20.,ACKTIM ; Yes - reset timer
BR 70$ ; & send pup out again
60$: MOV OUTLST,R3 ;Get message to send (if any)
BEQ DONE ; Nothing to send
MOV #OUTPUP,R1
JSR PC,SETOPUP ;Set up address info
MOVB #ALARM,OUTPUP+PUPTYP ;ALARM message
MOVB #ALPSIZ,OUTPUP+LENGTH ;ALARM message length
INC SEQOU2 ;Update output sequence number
ADC SEQOUT
MOV SEQOUT,OUTPUP+PUPID ; & stick it into pup id #
MOV SEQOU2,OUTPUP+PUPID2
MOV #OUTPUP+PDATA,R2 ;Start of pup data area
MOV #MSGSIZ/2-1,R0 ;Length of AL-ARM message in words
ADD #2,R3 ;Skip over local next pointer
62$: MOV (R3)+,(R2)+ ;Copy message into pup packet
SOB R0,62$
MOV OUTLST,R3 ;Advance output queue
MOV (R3),OUTLST
MOV R3,-(SP) ; & flush old message
MOV #MSGSIZ,R0 ;AL-ARM message size
JSR PC,$B72 ;Call DISPOSE
MOV #6,ACKTIM ;Set timers (first time is shorter)
MOV #20.,RETRY
70$: MOV #OUTPUP,R1
JSR PC,SNDPUP ;Send message out to AL
INC IOACT ; & set i/o flag
DONE: TST IOACT ;Did we do anything?
BEQ 90$ ; No
CLR TIMOUT ; Yes - reset time out counter
BR FIN ; & all done
90$: TST THEREC ;Are we awaiting an AL ALIVE reply?
BEQ 98$ ; No
SUB TICKS(SP),THEREC ; Yes - update timer
BGT FIN ; & keep waiting
MOV #2,R1 ;*** AL dead error
DEC THERER ;Time for retransmission?
BLE ALDEAD ; No - time-out, assume AL dead
97$: MOV #THRPUP,R1 ;See if AL is still alive
JSR PC,SETOPUP ;Set up address info
MOVB #THEREP,THRPUP+PUPTYP ;Ask AL to say it's still there
JSR PC,SNDPUP ;Send reply out
MOV #600.,THEREC ;Reset timer
BR FIN
98$: ADD TICKS(SP),TIMOUT ;Nothing happening - update counter
CMP #3600.,TIMOUT ;Has it been one minute yet?
BGT FIN ; No
MOV #6,THERER ; Yes - see if AL is still alive
BR 97$ ;(send 6 queries - one every 10 secs)
ALDEAD: MOV R1,@ABORTF ;*** Tell ARM to go into wait state
;;; INCB @ABORTF ;Tell ARM to go into wait state
MOV OUTLST,R3 ;Time-out, assume AL dead
1$: TST R3 ;Any output messages pending?
BEQ 2$ ; No
MOV R3,-(SP) ; Yes - flush them
MOV (R3),R3 ;Move on to next
MOV #MSGSIZ,R0 ;AL-ARM message size
JSR PC,$B72 ;Call DISPOSE
BR 1$
2$: CLR CONHST ;No connection open now
QIO$S #IO.KIL,#ENIN ;Flush any pending pup reads
FIN:
ENDPR
;Aux routine
READPU: CMPB #HELLOP,PUPTYP(R3) ;Someone trying to open a connection?
BNE 10$ ; No
MOV #BSYPUP,R1 ; Yes
JSR PC,SETOPUP ;Set up pup
MOV (R3),(R1) ;Use correct address info
SWAB (R1)
MOV SRCHST(R3),DSTHST(R1)
MOV SRCSOC(R3),DSTSOC(R1)
MOV SRCSC2(R3),DSTSC2(R1)
MOVB #ARMBSY,BSYPUP+PUPTYP ;Say ARM is busy
CMP SRCHST(R3),CONHST ;Check if same as current connection
BNE 5$ ; No
CMP SRCSOC(R3),CONSOC
BNE 5$ ; No
CMP SRCSC2(R3),CONSC2
BNE 5$ ; No
MOVB #ARMFRE,BSYPUP+PUPTYP ;Say ARM free - must be extra HELLO pup
5$: JSR PC,SNDPUP ;Send reply out
BR 99$ ; & all done
10$: CMPB #BYEBYE,PUPTYP(R3) ;AL going away?
BNE 20$ ; No
TST (SP)+ ; Yes - flush return address
MOV #3,R1
BR ALDEAD ; & quit
20$: CMPB #ALLIVE,PUPTYP(R3) ;Response to a THEREP pup?
BNE 30$ ; No
CLR THEREC ; Yes - clear time-out
BR 98$ ; & all done
30$: CMPB #ACK,PUPTYP(R3) ;An ACK?
BNE 40$ ; No
CMP SEQOUT,PUPID(R3) ; Yes - is it for last packet sent?
BNE 98$ ; No - a repeat
CMP SEQOU2,PUPID2(R3)
BNE 98$ ; No - a repeat
CLR ACKTIM ; Yes - clear ACK time-out
BR 98$ ; & all done
40$: CMPB #ALARM,PUPTYP(R3) ;A message for ARM?
BNE 99$ ; No - ignore it
MOV #ACKPUP,R1 ; Yes - send back an ACK
JSR PC,SETOPUP ;Set up address info
MOVB #ACK,ACKPUP+PUPTYP
MOV PUPID(R3),PUPID(R1) ;Set up sequence number
MOV PUPID2(R3),PUPID2(R1)
JSR PC,SNDPUP ;Send ACK out
CMP SEQIN,PUPID(R3) ;Have we seen this one yet?
BHI 98$ ; Yes - a repeat
CMP SEQIN2,PUPID2(R3)
BHIS 98$ ; Yes - a repeat
MOV PUPID(R3),SEQIN ; No - advance sequence number
MOV PUPID2(R3),SEQIN2
MOV INPMES,R1 ;Get AL-ARM message record
CLR (R1)+ ;Zero next pointer
ADD #PDATA,R3 ;R3 = Start of AL-ARM message
MOV #MSGSIZ/2-1,R0 ;Length in words of AL-ARM message
45$: MOV (R3)+,(R1)+ ;Copy AL-ARM message
SOB R0,45$
INC MESREC ;Indicate we got one
98$: INC IOACT ;Set I/O flag
99$: RTS PC
;Aux routins: SETOPUP & SNDPUP
;Aux routine to setup pup header for current connection
SETOPU: MOV R1,-(SP) ;Save pointer to pup
MOV CONDST,(R1)+
MOV #PUP,(R1)+ ;We're a pup
MOV #PUPOV,(R1)+ ;Assume length = pup overhead only
CLR (R1)+ ;Later need to set pup type
CLR (R1)+ ;Likewise for pup id
CLR (R1)+
MOV CONHST,(R1)+ ;Copy destination host/network
MOV CONSOC,(R1)+ ; & destination socket
MOV CONSC2,(R1)+ ; & destination socket
MOV HSTNUM,(R1)+ ;Copy server host/net info
CLR (R1)+
MOV #ARMSOC,(R1) ;Set source socket = ARM server
MOV (SP)+,R1 ;Restore pup pointer
RTS PC
;Aux routine to calculate pup checksum & send out pup
SNDPUP: MOV R0,-(SP) ;Save pointer to pup & other regs
MOV R2,-(SP)
MOV R1,-(SP)
ADD #4,R1 ;R1 = LOC(pup+length)
MOV (R1),R2 ;R2 = Pup length in bytes
INC R2 ;Get word count
ASR R2
DEC R2
CLR R0 ;Now compute checksum
1$: ADD (R1)+,R0 ;One's complement addition
ADC R0
ASL R0 ;Rotate left
ADC R0
SOB R2,1$
CMP R0,#177777 ;Change negative zero checksum to positive zero
BNE 2$
CLR R0
2$: MOV R0,(R1) ;Store away checksum
MOV (SP)+,R1 ;Retrieve pointer to pup
MOV 4(R1),R2 ;R2 = Pup length in bytes
ADD #4,R2 ;Add in overhead bytes
QIO$S #IO.WLB,#ENOUT,,,,,<R1,R2> ;Send out the pup packet to AL
MOV (SP)+,R2 ;Restore regs
MOV (SP)+,R0
RTS PC
.END